#pragma once

#include<iostream>
#include<string>
#include<functional>
#include<memory>
#include"Log.hpp"
#include"nocopy.hpp"
#include"Epoller.hpp"
#include"Socket.hpp"
#include"Comm.hpp"
#include<unordered_map>
#include<cerrno>


using namespace std;

class Connection;
class TcpServer;

uint32_t EVENT_IN = (EPOLLIN | EPOLLET);
uint32_t EVENT_OUT = (EPOLLOUT | EPOLLET);
const int buffer_size = 128;

using func_t = function<void(shared_ptr<Connection>)>;

class Connection
{
public:
    Connection(int sock, shared_ptr<TcpServer> tcp_server_ptr)
    :_sock(sock)
    ,_tcp_server_ptr(tcp_server_ptr)
    {}

    void SetHandle(func_t recv_cb, func_t send_cb, func_t exce_cb)
    {
        _recv_cb = recv_cb;
        _send_cb = send_cb;
        _exce_cb = exce_cb;
    }

    ~Connection()
    {}

    int SockFd()
    {
        return  _sock;
    }

    void AppendInbuffer(const string &info)
    {
        _inbuffer += info;
    }

    void AppendOutbuffer(const string &info)
    {
        _outbuffer+= info;
    }

    string& Inbuffer()
    {
        return _inbuffer;
    }

    string& OutBuffer()
    {
        return _outbuffer;
    }
private:
    int _sock;
    string _inbuffer; //string 二进制流 vector
    string _outbuffer;
public:
    func_t _recv_cb;
    func_t _send_cb;
    func_t _exce_cb;

    //添加一个回指指针
    shared_ptr<TcpServer> _tcp_server_ptr;
public:
    string _ip;
    uint16_t _port;
};

class TcpServer : Nocopy
{
    static const int num = 64;
public:
    TcpServer(uint16_t port, func_t OnMessage)
    :_port(port)
    ,_quit(true)
    ,_epoller_ptr(new Epoller())
    ,_listensock_ptr(new Sock())
    ,_OnMessage(OnMessage)
    {}

    ~TcpServer()
    {}
public:
    void Init()
    {
        _listensock_ptr->Socket();
        // _listensock_ptr->SetNonBolck();
        SetNonBolck(_listensock_ptr->GetFd());
        _listensock_ptr->Bind(_port);
        _listensock_ptr->Listen();
        lg(Info, "create listen sock succcess: %d\n", _listensock_ptr->GetFd());
        AddConnection(_listensock_ptr->GetFd(), EVENT_IN,\
        std::bind(&TcpServer::Accepter, this, placeholders::_1), nullptr, nullptr);
    }

    void AddConnection(int sock, uint32_t event, func_t recv_cb, func_t send_cb, func_t exce_cb)
    {
        //给listensock建立一个connection对象，同时将listensock和connection放入connections
        shared_ptr<Connection> new_connection = make_shared<Connection>(sock, shared_ptr<TcpServer>(this));
        new_connection->SetHandle(recv_cb, send_cb, exce_cb);
        //添加到unoredered_map
        _connections.insert(make_pair(sock, new_connection));
        //添加对应事件到内核中
        _epoller_ptr->EpllerUpdate(EPOLL_CTL_ADD, _listensock_ptr->GetFd(), EVENT_IN);
    }
    bool IsConnectionSafe(int fd)
    {
        auto iter = _connections.find(fd);
        if(iter == _connections.end()) 
            return false;
        return true;
    }

    void Accepter(shared_ptr<Connection> connection)
    {
        while(true)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sock = accept(connection->SockFd(), (struct sockaddr*)&peer, &len);
            
            if(sock > 0)
            {
                uint16_t peerport = ntohs(peer.sin_port);
                char ipbuffer[128];
                inet_ntop(AF_INET, &peer.sin_addr.s_addr, ipbuffer, sizeof(ipbuffer));
                string peerip = ipbuffer;
                lg(Debug, "get a new client, get info[%s:%d], sockfd:%d", ipbuffer, peerport, sock);

                // connection->_ip = ipbuffer;这里为何不能直接设后面看看
                // connection->_port = peerport;
                SetNonBolck(sock);
                AddConnection(sock, EVENT_IN,\
                bind(&TcpServer::Recver, this, placeholders::_1), 
                bind(&TcpServer::Sender, this, placeholders::_1),
                bind(&TcpServer::Excepter, this, placeholders::_1));
            }
            else
            {
                if(errno == EWOULDBLOCK) break;
                else if(errno == EINTR) continue;
                else break;
            }
        }
    }

    //事件管理器
    void Recver(shared_ptr<Connection> connection)
    {
        int sock = connection->SockFd();
        while(true)
        {
            char buffer[buffer_size];
            memset(buffer, 0, sizeof(buffer));
            ssize_t n = recv(sock, buffer, sizeof(buffer)-1, 0);
            if(n > 0){
                connection->AppendInbuffer(buffer);
            }
            else if(n == 0){
                lg(Info, "client info quit...");
                connection->_exce_cb(connection);
            }
            else{
                if(errno == EWOULDBLOCK) break;
                else if(errno == EINTR) continue;
                else{
                    lg(Warning, "client recv err...");
                    connection->_exce_cb(connection);
                }
                
            }
        }
        //数据有了但不一定全，需要检测
        _OnMessage(connection);//你独到的sock所有数据在connecion中
    }
    void Sender(shared_ptr<Connection> connection)
    {
        auto &outbuffer = connection ->OutBuffer();
        while(true)
        {
            ssize_t n = send(connection->SockFd(), outbuffer.c_str(), outbuffer.size(), 0);
            if(n > 0)
            {
                outbuffer.erase(0, n);
                if(outbuffer.empty()) break;
            }
            else if(n == 0)
            {
                return;
            }
            else
            {
                if(errno == EWOULDBLOCK) break;
                else if(errno == EINTR) continue;
                else{
                    lg(Warning, "send error");
                    connection->_exce_cb(connection);
                    return;
                }
            }
        }
        if(!outbuffer.empty())
        {
            //开启对写事件的关心
            EnableEvent(connection->SockFd(), true, true);
        }
        else
        {
            //关闭对写事件的关心
            EnableEvent(connection->SockFd(), true, false);
        }
    }


    void Excepter(shared_ptr<Connection> connection)
    {
        // lg(Debug, "client hander");
        //移除对特定fd关心
        // EnableEvent(connection->SockFd(), false, false);
        _epoller_ptr->EpllerUpdate(EPOLL_CTL_DEL, connection->SockFd(), 0);
        //关闭异常文件描述符
        close(connection->SockFd());
        //从unordered_map中移除
        // _connections.erase(connection->SockFd());
    }

    void EnableEvent(int sock, bool readable, bool writeable)
    {
        uint32_t events = 0;
        events |= (readable ? EPOLLIN:0) | (writeable?EPOLLOUT:0) | EPOLLET;
        _epoller_ptr->EpllerUpdate(EPOLL_CTL_MOD, sock, events);
    }

    void Dispatcher(int timeout)
    {
        int n = _epoller_ptr->EpollWait(revs, num, timeout);
        for(int i = 0; i<n; i++)
        {
            uint32_t events = revs[i].events;
            int sock = revs[i].data.fd;
            if(events & EPOLLERR) events |= (EPOLLIN | EPOLLOUT);
            if(events & EPOLLHUP) events |= (EPOLLIN | EPOLLOUT);
            if((events & EPOLLIN) && IsConnectionSafe(sock))
            {
                if(_connections[sock]->_recv_cb)
                    _connections[sock]->_recv_cb(_connections[sock]);
            }
            if((events & EPOLLOUT) && IsConnectionSafe(sock))
            {
                if(_connections[sock]->_send_cb)
                    _connections[sock]->_send_cb(_connections[sock]);
            }
        }
    }

    void Loop()
    {
        _quit = false;
        // _epoller_ptr->EpllerUpdate(EPOLL_CTL_ADD, _listensock_ptr->GetFd(), EVENT_IN);
        while(!_quit)
        {
            Dispatcher(3000);
        }
        _quit = true;
    }
private:
    shared_ptr<Epoller> _epoller_ptr;//内核
    unordered_map<int, shared_ptr<Connection>> _connections;
    shared_ptr<Sock> _listensock_ptr;//监听者
    struct epoll_event revs[num];
    uint16_t _port;
    bool _quit;

    //让上层处理信息
    func_t _OnMessage;
};